package com.sfexpress.tools;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.sfexpress.tools.entity.ConsCheckResult;
import com.sfexpress.tools.entity.ConsCheckResult.ConflictItem;
import com.sfexpress.tools.entity.ConsCheckResult.ItemResult;
import com.sfexpress.tools.entity.MysqlColumnInfo;
import com.sfexpress.tools.entity.MysqlTableInfo;
import com.sfexpress.tools.utils.Pair;
import com.sfexpress.tools.utils.SetUtil;

/**
 * 列定义一致性检查类
 * @author CrazyPig
 *
 */
public class MysqlColumnInfoChecker extends AbstractChecker {
	
	public void checkConsistency(MysqlTableInfo pvTableInfo, MysqlTableInfo gvTableInfo, ConsCheckResult result) {
		
		logger.info("开始进行列信息一致性校验 ...");
		
		Map<String, MysqlColumnInfo> pvColumnMap = getColumnInfoMap(pvTableInfo.getColumnInfoList());
		Map<String, MysqlColumnInfo> gvColumnMap = getColumnInfoMap(gvTableInfo.getColumnInfoList());
		
		Set<String> pvColumnSet = pvColumnMap.keySet();
		Set<String> gvColumnSet = gvColumnMap.keySet();
		
		Set<String> newItems = SetUtil.getDiffSet(gvColumnSet, pvColumnSet);
		if(newItems.size() > 0) { // has new items
//			result.setCoincident(false);
			logger.warn("检测到灰度版本表存在新列 : " + Arrays.toString(newItems.toArray()));
			result.getColInfoCheckResult().setCoincident(false);
			for(String newItem : newItems) {
				result.getColInfoCheckResult().getNewItems().add(gvColumnMap.get(newItem));
			}
		}
		
		Set<String> deletedItems = SetUtil.getDiffSet(pvColumnSet, gvColumnSet);
		if(deletedItems.size() > 0) { // has delete items
//			result.setCoincident(false);
			logger.warn("检测到灰度版本没有的列 : " + Arrays.toString(deletedItems.toArray()));
			result.getColInfoCheckResult().setCoincident(false);
			for(String deletedItem : deletedItems) {
				result.getColInfoCheckResult().getDeletedItems().add(pvColumnMap.get(deletedItem));
			}
		}
		
		Set<String> commItems = SetUtil.getInterSet(pvColumnSet, gvColumnSet);
		for(String item : commItems) {
			MysqlColumnInfo pvItem = pvColumnMap.get(item);
			MysqlColumnInfo gvItem = gvColumnMap.get(item);
			if(!checkConsistency(pvItem, gvItem, result)) {
				// 检测到列定义不一致
				logger.warn("检测到有不一致的列 : " );
				logger.warn("From 生产版本库 : " + pvItem);
				logger.warn("From 灰度版本库 : " + gvItem);
				result.getColInfoCheckResult().setCoincident(false);
				result.getColInfoCheckResult().getConflictItems().add(new Pair<MysqlColumnInfo, MysqlColumnInfo>(pvItem, gvItem));
			}
		}
		
		logger.info("列信息一致性校验结束!");
		
	}
	
	
	
	private boolean checkConsistency(MysqlColumnInfo pvColumnInfo, MysqlColumnInfo gvColumnInfo, ConsCheckResult result) {
		String columnName = pvColumnInfo.getColumnName();
		ItemResult<MysqlColumnInfo> colInfoCheckResult = result.getColInfoCheckResult();
		boolean flag = true;
		if(!StringUtils.equals(pvColumnInfo.getDataType(), gvColumnInfo.getDataType())) { // 数据类型一致性检查
			flag = false;
			colInfoCheckResult.addConflictItem(columnName, new ConflictItem(columnName, "DATE_TYPE", pvColumnInfo.getDataType(), gvColumnInfo.getDataType()));
		}
		if(!StringUtils.equals(pvColumnInfo.getColumnDefault(),gvColumnInfo.getColumnDefault())) {
			flag = false;
			colInfoCheckResult.addConflictItem(columnName, new ConflictItem(columnName, "COLUMN_DEFAULT", pvColumnInfo.getColumnDefault(), gvColumnInfo.getColumnDefault()));
		}
		if(!StringUtils.equals(pvColumnInfo.getIsNullable(), gvColumnInfo.getIsNullable())) {
			flag = false;
			colInfoCheckResult.addConflictItem(columnName, new ConflictItem(columnName, "IS_NULLABLE", pvColumnInfo.getIsNullable(), gvColumnInfo.getIsNullable()));
		}
		if(!StringUtils.equals(pvColumnInfo.getColumnType(), gvColumnInfo.getColumnType())) {
			flag = false;
			colInfoCheckResult.addConflictItem(columnName, new ConflictItem(columnName, "COLUMN_TYPE", pvColumnInfo.getColumnType(), gvColumnInfo.getColumnType()));
		}
		if(!StringUtils.equals(pvColumnInfo.getColumnKey(),gvColumnInfo.getColumnKey())) {
			flag = false;
			colInfoCheckResult.addConflictItem(columnName, new ConflictItem(columnName, "COLUMN_KEY", pvColumnInfo.getColumnKey(), gvColumnInfo.getColumnKey()));
		}
		if(!StringUtils.equals(pvColumnInfo.getExtra(),gvColumnInfo.getExtra())) {
			flag = false;
			colInfoCheckResult.addConflictItem(columnName, new ConflictItem(columnName, "EXTRA", pvColumnInfo.getExtra(), gvColumnInfo.getExtra()));
		}
		return flag;
	}
	
	private Map<String, MysqlColumnInfo> getColumnInfoMap(List<MysqlColumnInfo> columns) {
		return Maps.uniqueIndex(columns, new Function<MysqlColumnInfo, String>() {

			@Override
			public String apply(MysqlColumnInfo item) {
				return item.getColumnName();
			}
		});
	}
	
}
